﻿package com.urbansquall.serenity {
	import flash.utils.Dictionary;

public class EntityContainer
{
	private var m_entities : Array;
	private var m_idMap : Dictionary;
	
	private var m_entitiesToBeAdded : Array;
	private var m_entitiesToBeRemoved : Array;
	
	public function EntityContainer() 
	{
		m_entities = new Array();
		m_idMap = new Dictionary();
		
		m_entitiesToBeAdded = new Array();
		m_entitiesToBeRemoved = new Array();
	}
	
	public function dispose() : void
	{
		if( m_entities == null ) return; // already disposed
		
		processAddAndRemoves();
		
		var entityCount : int = m_entities.length;
		for( var entityIndex : int = entityCount - 1; entityIndex >= 0; entityIndex-- )
		{
			var entity : IEntity = m_entities[ entityIndex ];
			delete m_idMap[ entity.id ];
			entity.dispose();
		}
				
		m_entities.splice( 0 );
		m_entities = null;
		
		m_entitiesToBeAdded = null;
		m_entitiesToBeRemoved = null;
		
		m_idMap = null;
	}
	
	public function lookupEntity( a_id : String ) : IEntity	
	{
		return m_idMap[ a_id ];
	}
	
	public function getEntityAt( a_index : int ) : IEntity
	{
		return m_entities[ a_index ];
	}
	
	public function get numEntities() : int
	{
		return m_entities.length;
	}
	
	// The entity will not be added until the end of the frame
	public function addEntity( a_entity : IEntity ) : void
	{
		if( m_entitiesToBeAdded.indexOf( a_entity ) != -1 ) 
		{
			// throw new Error( "EntityContainer:addEntity. This entity is already queued for addition." );
			return;
		}
		if( m_idMap[ a_entity.id ] != null )
		{
			// throw new Error( "EntityContainer:addEntity. There is an entity with this id already. Ensure ids are unique." );
			return;
		}

		var entityCount : int = m_entitiesToBeAdded.length;
		for( var entityIndex : int = entityCount - 1; entityIndex >= 0; entityIndex-- )
		{
			var entity : IEntity = m_entitiesToBeAdded[ entityIndex ];
			if( entity.id == a_entity.id )
			{
				// throw new Error( "EntityContainer:addEntity. There is an entity with this id already. Ensure ids are unique." );				
				return;
			}
		}
		
		m_entitiesToBeAdded.push( a_entity );
	}
	
	// The entity will not be removed until the end of the frame	
	public function removeEntity( a_entity : IEntity ) : void
	{
		if( m_entitiesToBeRemoved.indexOf( a_entity ) != -1 ) 
		{
			// throw new Error( "EntityContainer:removeEntity. This entity is already queued for removal." );
			return;
		}
		if( m_idMap[ a_entity.id ] == null )
		{
			// throw new Error( "EntityContainer:removeEntity. There was no entity with a matching id." );
			return;
		}
					
		m_entitiesToBeRemoved.push( a_entity );		
	}
		
	public function tick( a_deltaTime : Number ) : void
	{		
		var entityCount : int = m_entities.length;
		for( var entityIndex : int = entityCount - 1; entityIndex >= 0; entityIndex-- )
		{
			var entity : IEntity = m_entities[ entityIndex ];
			entity.tick( a_deltaTime );
		}
		
		processAddAndRemoves();
	}
	
	private function processAddAndRemoves() : void
	{
		addNewEntities();				
		removeOldEntities();
	}
	
	private function removeOldEntities() : void
	{
		var entityCount : int = m_entitiesToBeRemoved.length;
		for( var entityIndex : int = entityCount - 1; entityIndex >= 0; entityIndex-- )
		{
			var entity : IEntity = m_entitiesToBeRemoved[ entityIndex ];
			
			var removalIndex : int = m_entities.indexOf( entity );
			if( removalIndex >= 0 )
			{
				m_entities.splice( removalIndex, 1 );
				delete m_idMap[ entity.id ];
			}
		}
		
		m_entitiesToBeRemoved.splice( 0 );
	}
	
	private function addNewEntities() : void
	{
		var entityCount : int = m_entitiesToBeAdded.length;
		for( var entityIndex : int = entityCount - 1; entityIndex >= 0; entityIndex-- )
		{
			var entity : IEntity = m_entitiesToBeAdded[ entityIndex ];
			m_idMap[ entity.id ] = entity;
			m_entities.push( entity );
		}
		
		m_entitiesToBeAdded.splice( 0 );
	}
	
	
}
	
}